﻿using System;
using System.Globalization;
using System.Text.RegularExpressions;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Media;
using Microsoft.VisualStudio.Text;
using Microsoft.VisualStudio.Text.Editor;
using Span = Microsoft.VisualStudio.Text.Span;


namespace XamlColorPreview
{
  ///<summary>
  ///XamlColorPreview draws a colored bar below all the binary Color notations in the editor window
  ///</summary>
  public class XamlColorPreview
  {

    IAdornmentLayer _layer;
    IWpfTextView _view;
    Pen _pen;
    Regex r = new Regex("#(([0-9A-Fa-f]){8}|([0-9A-Fa-f]){6})");

    public XamlColorPreview(IWpfTextView view)
    {
      _view = view;
      _layer = view.GetAdornmentLayer("XamlColorPreview");

      //Listen to any event that changes the layout (text changes, scrolling, etc)
      _view.LayoutChanged += OnLayoutChanged;

      Pen pen = new Pen(Brushes.Black, 0.5);
      pen.Freeze();
      _pen = pen;
    }

    /// <summary>
    /// On layout change add the adornment
    /// </summary>
    private void OnLayoutChanged(object sender, TextViewLayoutChangedEventArgs e)
    {
      IWpfTextViewLineCollection textViewLines = _view.TextViewLines;

      var matches = r.Matches(_view.TextSnapshot.GetText());
      foreach (Match match in matches)
      {
        // skip the starting #
        var span = new SnapshotSpan(_view.TextSnapshot, Span.FromBounds(match.Index + 1, match.Index + match.Length));
        var g = textViewLines.GetMarkerGeometry(span);
        if (g != null)
        {
          var txt = span.GetText();
          var brush = txt.Length == 6
           ? new SolidColorBrush(Color.FromRgb(
            Byte.Parse(txt.Substring(0, 2), NumberStyles.HexNumber),
            Byte.Parse(txt.Substring(2, 2), NumberStyles.HexNumber),
            Byte.Parse(txt.Substring(4, 2), NumberStyles.HexNumber)))
           : new SolidColorBrush(Color.FromArgb(
            Byte.Parse(txt.Substring(0, 2), NumberStyles.HexNumber),
            Byte.Parse(txt.Substring(2, 2), NumberStyles.HexNumber),
            Byte.Parse(txt.Substring(4, 2), NumberStyles.HexNumber),
            Byte.Parse(txt.Substring(6, 2), NumberStyles.HexNumber)));
          brush.Freeze();

          var drawing = new GeometryDrawing(brush, _pen, new RectangleGeometry(new Rect(g.Bounds.Left, g.Bounds.Bottom, g.Bounds.Width, 4)));
          drawing.Freeze();

          var drawingImage = new DrawingImage(drawing);
          drawingImage.Freeze();

          var image = new Image();
          image.Source = drawingImage;

          //Align the image with the top of the bounds of the text geometry
          Canvas.SetLeft(image, g.Bounds.Left);
          Canvas.SetTop(image, g.Bounds.Bottom - 4);

          _layer.AddAdornment(AdornmentPositioningBehavior.TextRelative, span, null, image, null);
        }
      }
    }
  }
}
